import time
from datetime import datetime

import pytz


class DateTimeCombiner:
    @staticmethod
    def combine(date_time_str, time_str):
        """
        将纯日期字符串和时间字符串组合成完整的ISO 8601格式的时间戳字符串

        参数:
            date_time_str (str): 日期字符串，格式如 '2025-03-20T00:00:00.000Z'
            time_str (str): 时间字符串，格式如 '08:00'

        返回:
            str: 组合后的ISO 8601格式的时间戳字符串，如 '2025-03-20T08:00:00.000Z'
        """
        try:
            # 解析日期部分
            dt = datetime.fromisoformat(date_time_str)

            # 解析时间部分
            hours, minutes = map(int, time_str.split(':'))

            # 替换时间为指定时间
            new_dt = dt.replace(hour=hours, minute=minutes)

            # 转换为ISO 8601格式字符串
            result = new_dt.isoformat()[:19] + ".000Z"

            return result

        except Exception as e:
            print(f"发生错误: {e}")
            return None

    @staticmethod
    def parse_iso_to_timestamp(dt_str):
        """
        将 ISO 8601 格式的日期时间字符串转换为 Unix 时间戳（秒级浮点数）。

        参数:
            dt_str (str): 需要转换的日期时间字符串，格式为 "YYYY-MM-DDTHH:MM:SS.mmmZ" 。

        返回:
            float: 转换后的时间戳（Unix 时间戳），如果解析失败则返回 None。
        """
        try:
            # 解析日期时间字符串
            dt = datetime.strptime(dt_str, "%Y-%m-%dT%H:%M:%S.%fZ")

            # 转换为 Unix 时间戳（秒级浮点数）
            timestamp = dt.timestamp()
            return timestamp
        except ValueError as e:
            print(f"解析日期时间字符串失败: {e}")
            return None

    @staticmethod
    def parse_iso_to_date(dt_str, fmt: str = "%Y-%m-%dT%H:%M:%S.%fZ"):
        return datetime.strptime(dt_str, fmt)

    @staticmethod
    def is_time_diff_over_second(target_time: datetime, diff_second: int, window_time: int = 15) -> dict:
        """判断时间与最近的15分钟整数窗口的距离是否超过1分钟"""
        # 计算总分钟数并四舍五入到最近的15分钟
        total_minutes = target_time.hour * 60 + target_time.minute
        nearest_15_min = round(total_minutes / window_time) * window_time

        # 构建最近的15分钟窗口时间（处理跨天情况）
        nearest_time = target_time.replace(
            hour=(nearest_15_min // 60) % 24,
            minute=nearest_15_min % 60,
            second=0,
            microsecond=0
        )

        # 计算时间差绝对值
        time_diff = abs(target_time - nearest_time)
        is_near = time_diff.total_seconds() <= diff_second
        is_floor = target_time >= nearest_time
        # 返回是否超过x秒
        return {'is_near': is_near, 'is_floor': is_floor}

    @staticmethod
    def is_same_day(date1:datetime, date2: datetime) -> dict:
        return date1.date() == date2.date()


def dynamic_format(original: str) -> str:
    parts = original.split(".")
    main = parts[0][:19] if len(parts[0]) >= 19 else parts[0].ljust(19, "0")
    frac = (parts[1][:3] if len(parts) > 1 else "000").ljust(3, "0")
    return f"{main}.{frac}Z"


def timestamp_to_ymd(timestamp, tz_name='Asia/Shanghai', is_millis=False):
    """支持时区转换的时间戳格式化

    Args:
        timestamp: 时间戳（默认秒级）
        tz_name: 时区名称，参考pytz.all_timezones
        is_millis: 是否为毫秒级时间戳

    Returns:
        str: 本地化时间字符串

    特性：支持1601条时区转换[[1-0]]
    """
    if is_millis:
        timestamp = timestamp / 1000
    utc_dt = datetime.fromtimestamp(timestamp, tz=pytz.timezone.utc)
    return utc_dt.astimezone(pytz.timezone(tz_name)).strftime('%Y%m%d')


def date_time_to_str_000z(time: datetime):
    return time.strftime('%Y-%m-%dT%H:%M:%S.000Z')


def timestamp_to_str_000z(current_timestamp: int):
    time = datetime.fromtimestamp(current_timestamp)
    return time.strftime('%Y-%m-%dT%H:%M:%S.000Z')


def timestamp_to_str(timestamp: float, format_str: str = "%Y-%m-%d %H:%M:%S") -> str:
    """
    将Unix时间戳转换为指定格式的日期字符串

    参数:
        timestamp (float): Unix时间戳（秒或毫秒级）
        format_str (str): 目标日期格式，默认"%Y-%m-%d %H:%M:%S"

    返回:
        str: 格式化后的日期字符串
    """
    # 自动识别时间戳单位（秒/毫秒）
    if timestamp > 1e11:
        timestamp /= 1000  # 毫秒转秒

    return datetime.fromtimestamp(timestamp).strftime(format_str)


def timestamp_to_date(current_timestamp: int):
    return datetime.fromtimestamp(current_timestamp)


def is_in_time_window(current_timestamp: int, clock_in_time: str, before_time_ms: int, after_time_ms: int) -> bool:
    """
    判断当前时间是否在目标时间点的前后偏移范围内
    :param current_timestamp:
    :param clock_in_time: 目标时间字符串（格式"HH:MM"）
    :param before_time_ms: 允许早于目标时间的最大毫秒数
    :param after_time_ms: 允许晚于目标时间的最小毫秒数
    :return: 是否在时间窗口内（布尔值）
    """
    # 获取当前本地时间
    now = timestamp_to_date(current_timestamp)

    # 解析输入时间为当天的datetime对象（无时区）
    clock_in = datetime.strptime(clock_in_time, "%H:%M").time()
    clock_in_today = datetime.combine(now.date(), clock_in)

    # 转换为时间戳（秒级精度）[6](
    clock_in_timestamp = clock_in_today.timestamp()

    # 计算时间窗口边界
    start_timestamp = clock_in_timestamp - (before_time_ms / 1000)
    end_timestamp = clock_in_timestamp + (after_time_ms / 1000)

    # 获取当前时间戳并判断区间
    current_timestamp = time.time()
    return start_timestamp <= current_timestamp <= end_timestamp
